/*    Copyright 2010 Tobias Marschall
 *
 *    This file is part of MoSDi.
 *
 *    MoSDi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    MoSDi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoSDi.  If not, see <http://www.gnu.org/licenses/>.
 */

package mosdi.index;

/** Class that reorders a string such that the characters belonging to 
 *  each prefix of the original string end up in the middle of the reordered
 *  string. Example: 0,1,2,3,4,5,6 --> 6,4,2,0,1,3,5. */
public class InsideOutReordering {

	private int length;
	private int[] originalString;
	private int[] reorderedString;
	private int[] reordering;
	private int[] inverseReordering;
	private boolean reverse;
	
	/** Constructor.
	 * @param reverse If reverse is true, then the reordered string is 
	 *                the reverse of the reordered string when reverse
	 *                is false.
	 */
	public InsideOutReordering(int[] originalString, boolean reverse) {
		this.length = originalString.length;
		this.originalString = originalString;
		this.reverse = reverse;
		reordering = new int[length];
		inverseReordering = new int[length];
		int basepos = reverse?length/2:(length-1)/2;
		for (int i=0; i<length; ++i) {
			int j;
			if (reverse) j = (i%2==0)?(basepos+i/2):(basepos-(i+1)/2);
			else j = (i%2==0)?(basepos-i/2):(basepos+(i+1)/2);
			reordering[i] = j;
			inverseReordering[j] = i;
		}
		reorderedString = new int[length];
		for (int i=0; i<length; ++i) {
			reorderedString[reordering[i]] = originalString[i];
		}
	}

	public int[] originalString() {
		return originalString;
	}
	
	public int[] reorderedString() {
		return reorderedString;
	}
	
	public void setPosition(int originalPosition, int newChar) {
		originalString[originalPosition] = newChar;
		reorderedString[reordering[originalPosition]] = newChar;
	}
	
	/** Every prefix of the original string corresponds to a substring of 
	 *  the reordered string; this method tells whether a character
	 *  appended to the original string's prefix is appended to the 
	 *  left of the reordered string (i.e. prepended). */
	public boolean appendedLeft(int originalPosition) {
		if ((originalPosition==0) || (originalPosition>=length)) throw new IllegalArgumentException();
		return reverse ^ (originalPosition%2==0);
	}
	
}
